#include <math.h>
#include <windows.h>
#include <stdio.h>

#include "config.h"
#include "event.h"
#include "util.h"
#include "obd_pid.h"

#define TWO_AXIS_DIFF_MIN 1000

int
main(int argc, char **argv)
{
	FILE *fpcfg, *fplog;
	char *cfg_file, *log_file;
	int r;
	struct config config;
	uint32_t next, file_size;
	int session_num;
	int cur_session;
	double time;
	int i, j;
	double min[NUM_LOG_SLOTS], max[NUM_LOG_SLOTS];
	int overall_min, overall_max;
	int firstrun[NUM_LOG_SLOTS];
	double xrange;
	int event_count;
	int axis_num[NUM_LOG_SLOTS];
	char *out_file;
	char *in_file;
	int xpixels;
		
	if (argc != 6) {
		fprintf(stderr, "usage: %s config_file log_file "
		    "in_file out_file session_num\n", argv[0]);
		exit(1);
	}

	cfg_file = argv[1];
	log_file = argv[2];
	in_file = argv[3];
	out_file = argv[4];
	session_num = atoi(argv[5]);

	fpcfg = fopen(cfg_file, "rb");
	if (fpcfg == NULL) {
		fprintf(stderr, "error: could not open %s\n", cfg_file);
		exit(1);
	}

	r = fread(&config, 1, sizeof(config), fpcfg);

	if (!valid_config(&config)) {
		fprintf(stderr, "error: invalid config read.\n");
		exit(1);
	}
	
	fplog = fopen(log_file, "rb");
	if (fplog == NULL) {
		fprintf(stderr, "error: could not open %s\n", log_file);
		exit(1);
	} 
	fseek(fplog, 0, SEEK_END);
	file_size = ftell(fplog);
	rewind(fplog);

	cur_session = 0;
	while (cur_session <= session_num) {
		r = fread(&next, 1, sizeof(next), fplog);
		if (r != sizeof(next)) {
			fprintf(stderr, "error: could not read next"
			    " address (session # too big)\n");
			exit(1);
		}

		if (cur_session == session_num)
			break;

		if (fseek(fplog, next, SEEK_SET) == -1) {
			fprintf(stderr, "error: could not seek next"
			    " address (session # too big)\n");
			exit(1);
		}

		++cur_session;
	}

	if (ftell(fplog) == file_size) {
		fprintf(stderr, "error: invalid session number\n");
		exit(1);
	}

	for (i = 0; i < NUM_LOG_SLOTS; ++i)
		firstrun[i] = 1;

	event_count = 0;
	
	time = 0;
	while (ftell(fplog) < next) {
		uint32_t data;
		double value;

		time += 0.5;

		for (i = 0; i < NUM_LOG_SLOTS; ++i) {
			if (config.event[i].interval == 0)
				continue;
			
			config.event[i].count++;

			if (config.event[i].count == config.event[i].interval) {
				config.event[i].count = 0;

				/* read the data, inc addr */
				data = 0;
				r = fread(&data, 1, PID_LENGTH(config.event[i].pid), fplog);
				if (r == 0) {
					fprintf(stderr, "error: read\n");
					exit(1);
				}

				if (PID_LENGTH(config.event[i].pid) == 2) {
					data = htons(data);
				} else if (PID_LENGTH(config.event[i].pid) == 4) {
					data = htonl(data);
				}

				value = conv_pid_data(config.event[i].pid, data);
				if (firstrun[i]) {
					min[i] = value;
					max[i] = value;
					firstrun[i] = 0;
					++event_count;
				} else {
					if (min[i] > value)
						min[i] = value;
					if (max[i] < value)
						max[i] = value;
				}
			}
		}
	}

	overall_min = 0;
	overall_max = 0;
	
	for (i = 0; i < NUM_LOG_SLOTS; ++i) {
		if (config.event[i].interval == 0)
			continue;

		if (min[overall_min] > min[i])
			overall_min = i;
		if (max[overall_max] < max[i])
			overall_max = i;
	}
	
	xrange = time;
#if 0
	for (i = 0; i < NUM_LOG_SLOTS; ++i) {
		if (config.event[i].interval == 0)
			continue;
		
		printf("min[%d]: %f\n", i, min[i]);
		printf("max[%d]: %f\n", i, max[i]);
	}

	printf("overall_min: %f\n", min[overall_min]);
	printf("overall_max: %f\n", max[overall_max]);
	printf("y range: %f\n", yrange);
	printf("xrange: %f\n", xrange);
	printf("%d events\n", event_count);
#endif
	for (i = 0; i < NUM_LOG_SLOTS; ++i)
		axis_num[i] = -1;

	axis_num[0] = 0;
	for (i = 1; i < NUM_LOG_SLOTS; ++i) {
		if (config.event[i].interval == 0)
			continue;

		for (j = 0; j < NUM_LOG_SLOTS; ++j) {
			if (config.event[j].interval == 0)
				continue;
			/*
			 * see if we wouldn't fit with a plot
			 * in axis 1. If we dont, go to axis 2
			 */
			if (axis_num[j] == 0) {
				if (abs(min[i] - min[j]) > TWO_AXIS_DIFF_MIN) {
					axis_num[i] = 1;
					break;
				} else if (abs(max[i] - max[j]) > TWO_AXIS_DIFF_MIN) {
					axis_num[i] = 1;
					break;
				} else {
					axis_num[i] = 0;
					break;
				}
			}
		}
	}

#define DIST_BETWEEN_POINTS 5
	xpixels = time * DIST_BETWEEN_POINTS;
	printf("#!/bin/sh\n\n");
	printf("echo 'set terminal png size %d; set output \"%s\"; set xtics 0, 20; set xlabel \"Time (s)\"; set grid; set xrange [%f:%f]; set y2tics border; plot", xpixels, out_file, 0.0, xrange);
	
	for (i = 0; i < NUM_LOG_SLOTS; ++i) {
		char *axis;
		if (config.event[i].interval == 0)
			continue;

		if (axis_num[i] == 0)
			axis = "x1y1";
		else
			axis = "x1y2";

		printf(" \"%s\" using 1:%d axis %s title \"%s (%s) %s\" with lines lw 3", in_file, i + 2, axis, pid_name[config.event[i].pid], pid_units(config.event[i].pid), axis);

		--event_count;

		if (event_count > 0)
			printf(",");
	}

	printf(";' | gnuplot\n");

	fclose(fpcfg);
	fclose(fplog);

	return 0;
}
